package com.mallcai.bigdata.ladon.service.report.impl;

import com.cake.bigdata.starter.exception.category.BusinessException;
import com.mallcai.bigdata.ladon.dpl.entity.report.QueryField;
import com.mallcai.bigdata.ladon.dpl.vo.DataType;
import com.mallcai.bigdata.ladon.dpl.vo.QueryFieldType;
import com.mallcai.bigdata.ladon.service.report.IParamGeneratorService;
import com.mallcai.bigdata.ladon.utils.CollectionUtils;
import com.mallcai.bigdata.ladon.utils.DateUtils;
import com.mallcai.bigdata.ladon.utils.SqlUtils;
import com.mallcai.bigdata.ladon.vo.QueryParamCollector;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author feixy
 * @version 1.0
 * @date 2019-07-18 16:35
 */
@Service
public class ParamGeneratorService implements IParamGeneratorService {

    @Override
    public QueryParamCollector generate(String  reportSql, List<QueryField> fieldList, Map<String, Object> params) {
        if(StringUtils.isEmpty(reportSql)){
            throw new BusinessException("sql不能为空");
        }
        QueryParamCollector ans = new QueryParamCollector(reportSql);

        List<String> paramNames = SqlUtils.parseParamName(reportSql);

        // 如果sql使用的参数为空,则完全不需要参数
        if(CollectionUtils.isEmpty(paramNames)){
            return ans;
        }
        List<String> unConfigParam = paramNames;
        Map<String, QueryField> queryFieldMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(fieldList)){
            fieldList.forEach(queryField -> queryFieldMap.put(queryField.getQueryName(), queryField));
            unConfigParam = paramNames.stream().filter(paramName -> !queryFieldMap.containsKey(paramName)).collect(Collectors.toList());
        }
        if(CollectionUtils.isNotEmpty(unConfigParam)){
            throw new BusinessException(String.format("以下参数[%s]未配置", CollectionUtils.join(unConfigParam, Function.identity())));
        }
        if(params == null){
            params = new HashMap<>();
        }

        Map<String,Object> singleParamValue = new HashMap<>();
        for (int i = 0; i < paramNames.size(); i++) {
            String key = paramNames.get(i);
            Object cacheValue = singleParamValue.get(key);
            QueryField queryField = queryFieldMap.get(key);

            if(cacheValue == null){
                Object value = params.get(key);
                DataType dataType = DataType.getByCode(queryField.getDataType());
                if (dataType == null){
                    throw new BusinessException(String.format("不支持的参数类型[%s]", queryField.getDataType()));
                }
                if(value == null){
                    value = convertDefaultValue(queryField.getValDefault(), dataType, queryField.getType()) ;
                }
                checkValue(key, value, dataType, queryField);
                singleParamValue.put(key, value);
                cacheValue = value;
            }

            QueryParamCollector.ParamHolder paramHolder = new QueryParamCollector.ParamHolder(key, cacheValue);
            paramHolder.setUsePlaceHolder(!QueryFieldType.contains(queryField.getType(), QueryFieldType.ORDER_BY));
            ans.add(paramHolder);
        }

        return ans;
    }

    private void checkValue(String paramName, Object value, DataType dataType, QueryField queryField) {
        if (value == null){
            throw new BusinessException(String.format("参数[%s]的值未指定",paramName));
        }
        // todo 最大值和最小值的判断
    }

    private Object convertDefaultValue(String value, DataType dataType, Integer type) {
       Object ans;
       if(QueryFieldType.contains(type, QueryFieldType.MULTIPLE) &&  StringUtils.isNotEmpty(value)){
           String[] split = StringUtils.split(value, ",");
           ans =  Arrays.stream(split).map(val-> convertSingleValue(value.trim(), dataType)).collect(Collectors.toList());
       } else {
           ans = convertSingleValue(value, dataType);
       }
       return ans;
    }

    private Object convertSingleValue(String value, DataType dataType){
        if(StringUtils.isEmpty(value)){
            return null;
        }
        Object ans = value;
        if(dataType == DataType.INTEGER){
            ans = Integer.valueOf(value);
        } else if (dataType == DataType.LONG){
            ans = Long.valueOf(value);
        } else if (dataType == DataType.FLOAT){
            ans =  Float.valueOf(value);
        } else if (dataType == DataType.DOUBLE){
            ans =  Double.valueOf(value);
        } else if (dataType == DataType.DATETIME){
            ans =  DateUtils.parseDate(value, DateUtils.NORMAL_DATE_FORMAT);
        } else if (dataType == DataType.DATE){
            ans =  DateUtils.parseDate(value, DateUtils.DATE_FORMAT_DATE);
        } else if (dataType == DataType.BOOLEAN){
            ans =  Boolean.valueOf(value);
        }
        return ans;
    }

}
